package cn.angis.system.controller;

import cn.angis.common.annotation.SLog;
import cn.angis.common.api.ApiErrorCode;
import cn.angis.common.constant.Constant;
import cn.angis.common.constant.Crypto;
import cn.angis.common.model.R;
import cn.angis.db.controller.BaseController;
import cn.angis.db.model.PageModel;
import cn.angis.db.model.PageOfResult;
import cn.angis.system.dto.input.PasswordInput;
import cn.angis.system.dto.input.UserInput;
import cn.angis.system.dto.output.UserOutput;
import cn.angis.system.dtomapper.UserStruct;
import cn.angis.system.model.AngisUser;
import cn.angis.system.service.AngisUserService;
import cn.angis.system.service.UserpostService;
import cn.angis.system.service.UserroleService;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.openjava.gmsm.sm2.SM2;
import cn.openjava.gmsm.sm3.SM3;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.noear.solon.annotation.*;
import org.noear.solon.cloud.model.Media;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.DownloadedFile;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.validation.annotation.NotBlank;
import org.noear.solon.validation.annotation.NotEmpty;
import org.noear.solon.validation.annotation.Validated;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 系统用户前端控制器
 * @author angis.cn
 * @Date 2022/12/30
 */
@SLog("用户管理")
@Mapping("/system/user/")
@Controller
public class UserController extends BaseController<AngisUserService, AngisUser> {

    @Inject
    private UserpostService userpostService;
    @Inject
    private UserroleService userroleService;

    /**
     * 分页查询
     * @param userInput
     * @param pageModel
     * @return R<PageResult<SysUserOutput>>
     * @Date: 2022/12/30
     */
    @Get
    @SLog
    @Mapping("page")
    public R<PageOfResult<AngisUser>> page(UserInput userInput, PageModel pageModel) {
        return success(pageListByEntity(userInput, pageModel));
    }

    /**
     * 保存用户
     * @param userInput
     * @return R<Boolean>
     * @Date 2022/12/31
     */
    @Post
    @SLog
    @Mapping("save")
    public R<Boolean> save(@Validated UserInput userInput) {
        AngisUser angisUser = UserStruct.INSTANCE.toUser(userInput);
        angisUser.setPassword(SM3.getDigest(getDefaultPass(angisUser.getUsername())));
        R<Boolean> result = super.save(angisUser);
        userpostService.saveUserPost(angisUser.getId(), userInput.getPostIds());
        userroleService.saveUserRole(angisUser.getId(), userInput.getRoleIds());
        return result;
    }

    /**
     * 修改
     * @param userInput
     * @return R<Boolean>
     * @Date 2022/12/31
     */
    @Post
    @SLog
    @Mapping("update")
    public R<Boolean> update(@Validated UserInput userInput) {
        AngisUser angisUser = UserStruct.INSTANCE.toUser(userInput);
        userpostService.saveUserPost(angisUser.getId(), userInput.getPostIds());
        userroleService.saveUserRole(angisUser.getId(), userInput.getRoleIds());
        return super.update(angisUser);
    }

    /**
     * 修改密码
     * @param passwordInput
     * @return: R<Boolean>
     * @throws:
     * @Date: 2023/1/7
     */
    @Post
    @SLog
    @Mapping("updatePassword")
    public R<Boolean> updatePassword(@Validated PasswordInput passwordInput) {
        AngisUser angisUser = baseService.getById(passwordInput.getUserId());
        if (!angisUser.getPassword().equals(SM3.getDigest(SM2.decrypt(passwordInput.getCurrentPass(), Crypto.PRIVATEKEY)))) {
            return R.error(ApiErrorCode.USER_UPDATE_PASS_ERROR);
        }
        passwordInput.setNewPass(SM2.decrypt(passwordInput.getNewPass(), Crypto.PRIVATEKEY));
        passwordInput.setConfPass(SM2.decrypt(passwordInput.getConfPass(), Crypto.PRIVATEKEY));
        if (!passwordInput.getNewPass().equals(passwordInput.getConfPass())) {
            return R.error(ApiErrorCode.USER_UPDATE_PASS2_ERROR);
        }
        AngisUser angisUserUpdate = new AngisUser();
        angisUserUpdate.setId(passwordInput.getUserId());
        angisUserUpdate.setPassword(SM3.getDigest(passwordInput.getNewPass()));
        return super.update(angisUserUpdate);
    }

    /**
     * 重置密码
     * @param userId
     * @param password
     * @return: R<Boolean>
     * @throws:
     * @Date: 2023/1/7
     */
    @Post
    @SLog
    @Mapping("resetPassword")
    public R<Boolean> resetPassword(@NotBlank String userId, @NotBlank String password) {
        AngisUser angisUser = new AngisUser();
        angisUser.setId(userId);
        angisUser.setPassword(SM3.getDigest(password));
        return super.update(angisUser);
    }

    /**
     * 根据用户名获取用户信息
     * @param username
     * @return: R<UserOutput>
     * @throws:
     * @Date: 2023/1/7
     */
    @Get
    @Mapping("getByUserName")
    public R<UserOutput> getByUsername(@NotBlank String username) {
        return success(UserStruct.INSTANCE.toOutput(baseService.getByUserName(username)));
    }

    /**
     * 获取在线用户列表
     * @return: R<List<User>>
     * @throws:
     * @Date: 2023/1/7
     */
    @Get
    @Mapping("getOnLineList")
    public R<List<UserOutput>> getOnLineUserList() {
        List<String> list = StpUtil.searchSessionId("", 0, 100, true);
        final int index = 3;
        List<String> collect = list.stream().map(s -> {
            List<String> split = Arrays.stream(StringUtils.split(s, ':')).toList();
            if (StringUtils.isNotBlank(CollectionUtils.get(split, index))) {
                return CollectionUtils.get(split, index);
            }
            return null;
        }).collect(Collectors.toList());
        return success(UserStruct.INSTANCE.toOutputList(super.listByIds(AngisUser.class, collect)));
    }

    /**
     * 删除
     * @param id
     * @return R<Boolean>
     * @Date 2022/12/31
     */
    @Post
    @SLog
    @Mapping("delete")
    public R<Boolean> delete(@NotBlank String id) {
        return super.delete(id);
    }

    /**
     * 批量删除
     * @param ids
     * @return R<Boolean>
     * @Date 2023/1/1
     */
    @Post
    @SLog
    @Mapping("deleteBatch")
    public R<Boolean> deleteBatch(@NotEmpty List<String> ids) {
        return super.deleteBatch(ids);
    }

    @Get
    @Mapping("getRoleListString")
    public R<List<String>> getRoleListString(@NotBlank String id) {
        return success(baseService.getRoleListByUserId(id));
    }

    @Get
    @Mapping("getPostListString")
    public R<List<String>> getPostListString(@NotBlank String id) {
        return success(baseService.getPostListByUserId(id));
    }

    @Post
    @Mapping("/upload")
    public R<Object> upload(UploadedFile file) {
        return uploadOss(file, "user");
    }

    @Post
    @Mapping("/upload64")
    public R<String> upload64(String base64) {
        String userurl = base64ToImage(base64, "user");
        SaSession session = StpUtil.getSession();
        String userId = (String) session.get(Constant.SESSION_USER_ID);
        AngisUser angisUser = getById(userId);
        angisUser.setAvatarUrl(userurl);
        update(angisUser);
        return success(userurl);
    }

    @Get
    @Mapping("/down")
    public void down(Context ctx, String key) {
        try {
            Media media = downOss(key);
            DownloadedFile file = new DownloadedFile(media.contentType(), media.body(), key);
            ctx.outputAsFile(file);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private String getDefaultPass(String name) {
        return "123456";
//        return name.toUpperCase() + name.toLowerCase() + "@387";
    }

    @Mapping("list")
    @Get
    public R<List<UserOutput>> list(UserInput userInput) {
        return success(baseService.selectUserList(userInput));
    }

}
